using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using System.Text;
using Me.Prettyprint.Cassandra.Utils;
using Me.Prettyprint.Cassandra.Serializers;
using Me.Prettyprint.Hector.Api.Ddl;

namespace Me.Prettyprint.Hector.Api.Beans
{
    /// <summary>
    /// Parent class of Composite and DynamicComposite. Acts as a list of objects
    /// that get serialized into a composite column name. Unless
    /// setAutoDeserialize(true) is called, it's going to try to match serializers to
    /// Cassandra comparator types.
    /// </summary>
	[Serializable]
	public abstract class AbstractComposite
	{
		public static Logger logger = new Logger(typeof(AbstractComposite));

        public static Dictionary<Type, string> DEFAULT_SERIALIZER_TO_COMPARATOR_MAPPING = new Dictionary<Type, string>()
        {
            {typeof(AsciiSerializer),AsciiSerializer.Instance.ComparatorType.TypeName},
            {typeof(BigIntegerSerializer),BigIntegerSerializer.Instance.ComparatorType.TypeName},
            {typeof(BytesArraySerializer),BytesArraySerializer.Instance.ComparatorType.TypeName},
            {typeof(LongSerializer),LongSerializer.Instance.ComparatorType.TypeName},
            {typeof(StringSerializer),StringSerializer.Instance.ComparatorType.TypeName},
            {typeof(UUIDSerializer),UUIDSerializer.Instance.ComparatorType.TypeName},
            {typeof(TimeUUIDSerializer), TimeUUIDSerializer.Instance.ComparatorType.TypeName}
        };
        public static Dictionary<Type, object> SERIALIZERS = new Dictionary<Type, object>()
        {
            {typeof(AsciiSerializer),AsciiSerializer.Instance},
            {typeof(BigIntegerSerializer),BigIntegerSerializer.Instance},
            {typeof(BytesArraySerializer),BytesArraySerializer.Instance},
            {typeof(LongSerializer),LongSerializer.Instance},
            {typeof(StringSerializer),StringSerializer.Instance},
            {typeof(UUIDSerializer),UUIDSerializer.Instance},
            {typeof(TimeUUIDSerializer),TimeUUIDSerializer.Instance}
        };
        public static Dictionary<byte, string> DEFAULT_ALIAS_TO_COMPARATOR_MAPPING = new Dictionary<byte, string>()
        {
            {(byte)'a',ComparatorType.ASCIITYPE.TypeName},
            {(byte)'b',ComparatorType.BYTESTYPE.TypeName},
            {(byte)'i',ComparatorType.INTEGERTYPE.TypeName},
            {(byte)'x',ComparatorType.LEXICALUUIDTYPE.TypeName},
            {(byte)'z',ComparatorType.DATETYPE.TypeName},
            {(byte)'l',ComparatorType.LONGTYPE.TypeName},
            {(byte)'t',ComparatorType.TIMEUUIDTYPE.TypeName},
            {(byte)'s',ComparatorType.UTF8TYPE.TypeName},
            {(byte)'u',ComparatorType.UUIDTYPE.TypeName}
        };
        public static Dictionary<string, byte> DEFAULT_COMPARATOR_TO_ALIAS_MAPPING = new Dictionary<string, byte>()
        {
            {ComparatorType.ASCIITYPE.TypeName,(byte)'a'},
            {ComparatorType.BYTESTYPE.TypeName,(byte)'b'},
            {ComparatorType.INTEGERTYPE.TypeName,(byte)'i'},
            {ComparatorType.LEXICALUUIDTYPE.TypeName,(byte)'x'},
            {ComparatorType.DATETYPE.TypeName,(byte)'z'},
            {ComparatorType.LONGTYPE.TypeName,(byte)'l'},
            {ComparatorType.TIMEUUIDTYPE.TypeName,(byte)'t'},
            {ComparatorType.UTF8TYPE.TypeName,(byte)'s'},
            {ComparatorType.UUIDTYPE.TypeName,(byte)'u'}
        };
        public static Dictionary<string, object> COMPARATOR_TO_SERIALIZER_MAPPING = new Dictionary<string, object>()
        {
            {ComparatorType.ASCIITYPE.TypeName,AsciiSerializer.Instance},
            {ComparatorType.BYTESTYPE.TypeName,BytesArraySerializer.Instance},
            {ComparatorType.INTEGERTYPE.TypeName,IntegerSerializer.Instance},
            {ComparatorType.LEXICALUUIDTYPE.TypeName,UUIDSerializer.Instance},
            {ComparatorType.LONGTYPE.TypeName,LongSerializer.Instance},
            {ComparatorType.TIMEUUIDTYPE.TypeName,UUIDSerializer.Instance},
            {ComparatorType.UTF8TYPE.TypeName,StringSerializer.Instance},
            {ComparatorType.UUIDTYPE.TypeName,UUIDSerializer.Instance}
        };
        public AbstractComposite()
        {
            Components = new List<object>();
        }
        public AbstractComposite(bool dynamic, List<object> list) : this()
        {
            Dynamic = dynamic;
            foreach (object t in list)
            {
                AddComponent(t);
            }
        }
        public AbstractComposite(bool dynamic) : this()
        {
            Dynamic = dynamic;
        }
        public AbstractComposite(List<object> list) : this()
        {
            foreach (object t in list)
            {
                AddComponent(t);
            }
        }
        public AbstractComposite(params object[] varargs)
            : this()
        {
            foreach (object t in varargs)
            {
                AddComponent(t);
            }
        }
        public ComponentEquality Equality
        {
            get;
            set;
        }
        public List<object> Components
        {
            get;
            set;
        }
        public bool Dynamic
        {
            get;
            protected set;
        }
        public List<object> SerializersByPosition
        {
            get;
            set;
        }
        public List<string> ComparatorsByPosition
        {
            get;
            set;
        }
        public ByteBuffer Serialized
        {
            get;
            set;
        }
        public Dictionary<Type, string> SerializerToComparatorDictionary
        {
            get;
            set;
        }
        public Dictionary<byte, string> AliasToComparatorDictionary
        {
            get;
            set;
        }
        public void SetSerializerByPosition<T>(int index, Serializer<T> s)
        {
            if (SerializersByPosition == null)
            {
                SerializersByPosition = new List<object>();
            }
            while (SerializersByPosition.Count <= index)
            {
                SerializersByPosition.Add(null);
            }
            SerializersByPosition[index] = s;
        }
        public void setComparatorByPosition(int index, string c)
        {
            if (ComparatorsByPosition == null)
            {
                ComparatorsByPosition = new List<string>();
            }
            while (ComparatorsByPosition.Count <= index)
            {
                ComparatorsByPosition.Add(null);
            }
            ComparatorsByPosition[index] = c;
        }
        public int CompareTo(AbstractComposite o)
        {
            return Serialized.CompareTo(o.Serialized);
        }
        private string ComparatorForSerializer<T>(Serializer<T> serializer)
        {
            string comparator = SerializerToComparatorDictionary[serializer.GetType()];
            if (comparator != null)
            {
                return comparator;
            }
            return ComparatorType.BYTESTYPE.TypeName;
        }
        private Serializer<T> SerializerForComparator<T>(string c)
        {
            int p = c.IndexOf('(');
            if (p >= 0)
            {
                c = c.Substring(0, p);
            }
            if (ComparatorType.TIMEUUIDTYPE.TypeName.Equals(c))
            {
                return (Serializer<T>)UUIDSerializer.Instance;
            }
            Serializer<T> s = (Serializer<T>)COMPARATOR_TO_SERIALIZER_MAPPING[c];
            if (s != null)
            {
                return s;
            }
            return (Serializer<T>)BytesArraySerializer.Instance;
        }
        private Serializer<T> SerializerForPosition<T>(int i)
        {
            if (SerializersByPosition == null)
            {
                return null;
            }
            if (i >= SerializersByPosition.Count) 
            {
                return null;
            }
            return (Serializer<T>)SerializersByPosition[i];
        }
        private Serializer<T> GetSerializer<T>(int i, string c)
        {
            Serializer<T> s = SerializerForPosition<T>(i);
            if (s != null) 
            {
                return s;
            }
            return SerializerForComparator<T>(c);
        }
        private string ComparatorForPosition(int i)
        {
            if (ComparatorsByPosition == null)
            {
                return null;
            }
            if (i >= ComparatorsByPosition.Count)
            {
                return null;
            }
            return ComparatorsByPosition[i];
        }
        public void Clear()
        {
            Serialized = null;
            Components = new List<object>();
        }
        public virtual AbstractComposite AddComponent<T>(T element)
        {
            Serializer<T> srzr = SerializerTypeInferer.GetSerializer<T>(element);
            string comparatorName = srzr.GetComparatorType().TypeName;
            ComparatorsByPosition.Add(comparatorName);
            Component<T> newComp = new Component<T>(element, null, srzr, comparatorName, ComponentEquality.EQUAL);
            Components.Add(newComp);
            return this;
        }
        public AbstractComposite AddComponent<T>(int index, T element, ComponentEquality equality)
        {
            Serialized = null;
            Serializer<T> srzr = SerializerForPosition<T>(index);
            if (srzr == null) 
            {
                srzr = SerializerTypeInferer.GetSerializer<T>(element);
            }
            string comparatorName = ComparatorForPosition(index);
            if (comparatorName == null)
            {
                comparatorName = ComparatorForSerializer(srzr);
                ComparatorsByPosition.Add(comparatorName);
            }
            Component<T> newComponent = new Component<T>(element, null, srzr, comparatorName, equality);
            Components[index] = newComponent;
            SetSerializerByPosition<T>(index, srzr);
            return this;
        }
        /// <summary>
        /// Due to differences between Java and C# generics, I split the logic in
        /// AddComponent(int, T, ComponentEquality) into 2 methods. This second
        /// one takes Component&lt;T&gt; for the second parameter.
        /// </summary>
        /// <param name="index"></param>
        /// <param name="element"></param>
        /// <param name="equality"></param>
        /// <returns></returns>
        public AbstractComposite AddComponent<T>(int index, Component<T> element, ComponentEquality equality)
        {
            Components[index] = element;
            return this;
        }
        public AbstractComposite AddComponent<T>(T value, Serializer<T> s)
        {
            return AddComponent(value, s, ComparatorForSerializer(s));
        }
        public AbstractComposite AddComponent<T>(T value, Serializer<T> s, string comparator)
        {
            AddComponent(value, s, comparator, ComponentEquality.EQUAL);
            return this;
        }
        public AbstractComposite AddComponent<T>(T value, Serializer<T> s, string comparator, ComponentEquality equality)
        {
            AddComponent(-1, value, s, comparator, equality);
            return this;
        }
        public AbstractComposite AddComponent<T>(int index, T value, Serializer<T> s, string comparator, ComponentEquality equality)
        {
            if (value == null)
            {
                throw new System.NullReferenceException("Unable able to add null component");
            }

            if (index < 0)
            {
                index = Components.Count;
            }
            while (Components.Count < (index + 1))
            {
                Components.Add(null);
                SerializersByPosition.Add(null);
            }
            // We use SerializerTypeInferrer to determine the right concrete Serializer and then get the TypeName
            comparator = SerializerTypeInferer.GetSerializer<T>(value).GetComparatorType().TypeName;
            Components[index] = new Component<T>(value, null, s, comparator, equality);
            SerializersByPosition[index] = s;
            return this;
        }
        private static object MapIfNumber(object o)
        {
            if ((o is int) || (o is short))
            {
                return (int)o;
            }
            else if (o is byte)
            {
                byte[] bytes = new byte[] {(byte)o};
                BigInteger bi = new BigInteger(bytes);
                return (long)bi;
            }
            return o;
        }
        private static System.Collections.IList Flatten(System.Collections.IList c)
        {
            if (c is AbstractComposite) 
            {
                return ((AbstractComposite)c).Components;
            }
            bool hasCollection = false;
            foreach (object o in c)
            {
                if (o is IList)
                {
                    hasCollection = true;
                    break;
                }
            }
            if (!hasCollection)
            {
                return c;
            }
            IList newList = new ArrayList();
            foreach (object o in c)
            {
                if (o is IList)
                {
                    IList nested = Flatten((IList)o);
                    foreach (object nestedobj in nested)
                    {
                        newList.Add(nestedobj);
                    }
                }
                else
                {
                    newList.Add(o);
                }
            }
            return newList;
        }
        public void add(int index, object element)
        {
            element = MapIfNumber(element);
            AddComponent(index, element, ComponentEquality.EQUAL);
        }
        public AbstractComposite SetComponent<T>(int index, T value, Serializer<T> s)
        {
            SetComponent(index, value, s, ComparatorForSerializer(s));
            return this;
        }
        public AbstractComposite SetComponent<T>(int index, T value, Serializer<T> s, string comparator)
        {
            SetComponent(index, value, s, comparator, ComponentEquality.EQUAL);
            return this;
        }
        public AbstractComposite SetComponent<T>(int index, T value, Serializer<T> s, string comparator, ComponentEquality equality)
        {
            Serialized = null;
            while (Components.Count <= index)
            {
                Components.Add(null);
            }
            // We use SerializerTypeInferrer to determine the right concrete Serializer and then get the TypeName
            comparator = SerializerTypeInferer.GetSerializer<T>(value).GetComparatorType().TypeName; 
            Components[index] = new Component<T>(value, null, s, comparator, equality);
            return this;
        }
        public T get<T>(int i)
        {
            Component<T> c = (Component<T>)Components[i];
            if (c != null)
            {
                return c.Value;
            }
            return default(T);
        }
        public object Get<T>(int i, Serializer<T> s)
        {
            object value = null;
            Component<T> c = (Component<T>)Components[i];
            if (c != null)
            {
                value = c.GetValue(s);
            }
            return value;
        }
        public Component<T> GetComponent<T>(int i)
        {
            if (i >= Components.Count)
            {
                return null;
            }
            // Note: after the query returns and creates the DynamicComposite, it is BytesType need to figure out why
            Component<T> c = (Component<T>)Components[i];
            return c;
        }
        /// <summary>
        /// Due to the differences between Java and C#, we can't use wildcard Generics like Hector.
        /// Instead, we have to loop through the components list and check the type explicitly
        /// </summary>
        /// <returns></returns>
        public ByteBuffer Serialize()
        {
            if (Serialized != null)
            {
                return Serialized.Duplicate();
            }
            ByteBufferOutputStream bbos = new ByteBufferOutputStream();
            int i = 0;
            foreach (object comp in Components)
            {
                ByteBuffer bbuf = null;
                string comparator = null;
                ComponentEquality compEq = ComponentEquality.EQUAL;
                if (comp is Component<int>)
                {
                    Serializer<int> s = SerializerForPosition<int>(i);
                    Component<int> intcomp = (Component<int>)comp;
                    bbuf = intcomp.GetValueByteBuffer(s);
                    comparator = IntegerSerializer.Instance.GetComparatorType().TypeName;
                    compEq = intcomp.Equality;
                }
                else if (comp is Component<long>)
                {
                    Serializer<long> s = SerializerForPosition<long>(i);
                    Component<long> longcomp = (Component<long>)comp;
                    bbuf = longcomp.GetValueByteBuffer(s);
                    comparator = LongSerializer.Instance.GetComparatorType().TypeName;
                    compEq = longcomp.Equality;
                }
                else if (comp is Component<BigInteger>)
                {
                    Serializer<BigInteger> s = SerializerForPosition<BigInteger>(i);
                    Component<BigInteger> bicomp = (Component<BigInteger>)comp;
                    bbuf = bicomp.GetValueByteBuffer(s);
                    comparator = BigIntegerSerializer.Instance.GetComparatorType().TypeName;
                    compEq = bicomp.Equality;
                }
                else if (comp is Component<string>)
                {
                    Serializer<string> s = SerializerForPosition<string>(i);
                    Component<string> stcomp = (Component<string>)comp;
                    bbuf = stcomp.GetValueByteBuffer(s);
                    comparator = StringSerializer.Instance.GetComparatorType().TypeName;
                    compEq = stcomp.Equality;
                }
                else if (comp is Component<Guid>)
                {
                    Serializer<Guid> s = SerializerForPosition<Guid>(i);
                    Component<Guid> gdcomp = (Component<Guid>)comp;
                    bbuf = gdcomp.GetValueByteBuffer(s);
                    comparator = UUIDSerializer.Instance.GetComparatorType().TypeName;
                    compEq = gdcomp.Equality;
                }
                else if (comp is Component<DateTime>)
                {
                    Serializer<DateTime> s = SerializerForPosition<DateTime>(i);
                    Component<DateTime> dtcomp = (Component<DateTime>)comp;
                    bbuf = dtcomp.GetValueByteBuffer(s);
                    comparator = DateSerializer.Instance.GetComparatorType().TypeName;
                    compEq = dtcomp.Equality;
                }
                if (bbuf == null)
                {
                    bbuf = new ByteBuffer(0);
                }
                if (Dynamic)
                {
                    if (comparator == null)
                    {
                        comparator = ComparatorType.BYTESTYPE.TypeName;
                    }
                    int p = comparator.IndexOf("(reversed=true)");
                    bool desc = false;
                    if (p >= 0)
                    {
                        comparator = comparator.Substring(0, p);
                        desc = true;
                    }
                    if (DEFAULT_COMPARATOR_TO_ALIAS_MAPPING.ContainsKey(comparator)) 
                    {
                        byte a = DEFAULT_COMPARATOR_TO_ALIAS_MAPPING[comparator];
                        if (desc) 
                        {
                            a = (byte) char.ToUpper((char) a);
                        }
                        bbos.WriteShort((short) (0x8000 | a));
                    } 
                    else
                    {
                        bbos.WriteShort((short) comparator.Length);
                        byte[] cbarray = StringSerializer.Instance.ToBytes(comparator);
                        bbos.Write(cbarray);
                    }
                }
                bbos.WriteShort((short) bbuf.Remaining());
                bbos.WriteByteBuffer(bbuf.Slice());

                if ((i == (Components.Count - 1)) && (Equality != ComponentEquality.EQUAL)) 
                {
                    bbos.WriteByte(ConvertComponentEqualityToByte(Equality));
                }
                else
                {
                    bbos.WriteByte(ConvertComponentEqualityToByte(compEq));
                }
                i++;
            }
            Serialized = bbos.GetAllBytes();
            return Serialized.Duplicate();
        }
        /// <summary>
        /// Due to differences between Java and C# generics, we can't use wildcard to
        /// handle deserialization. Instead we have to get the comparator and do an
        /// ugly if/else if/else block to convert the bytes back to the original values.
        /// </summary>
        /// <param name="bbuf"></param>
        public void Deserialize(ByteBuffer bbuf)
        {
            ByteBuffer bytescopy = bbuf.Duplicate();
            Serialized = bytescopy;
            Components = null;
            Components = new List<object>();
            string comparator = null;
            int i = 0;
            while ((comparator = GetComparator(i, bytescopy)) != null)
            {
                ByteBuffer data = GetWithShortLength(bytescopy);
                ComponentEquality equality = ComponentEquality.EQUAL;
                ByteBuffer slice = null;
                if (data != null)
                {
                    if (comparator.Equals(ComparatorType.ASCIITYPE.TypeName))
                    {
                        Serializer<string> s = AsciiSerializer.Instance;
                        equality = GetComponentEquality(bytescopy.Get());
                        slice = data.Slice();
                        Component<string> comp = new Component<string>(null, slice, s, comparator, equality);
                        Components.Add(comp);
                    }
                    else if (comparator.Equals(ComparatorType.UTF8TYPE.TypeName))
                    {
                        Serializer<string> s = StringSerializer.Instance;
                        equality = GetComponentEquality(bytescopy.Get());
                        slice = data.Slice();
                        Component<string> comp = new Component<string>(null, slice, s, comparator, equality);
                        Components.Add(comp);
                    }
                    else if (comparator.Equals(ComparatorType.BYTESTYPE.TypeName))
                    {
                        Serializer<byte[]> s = BytesArraySerializer.Instance;
                        equality = GetComponentEquality(bytescopy.Get());
                        slice = data.Slice();
                        Component<byte[]> comp = new Component<byte[]>(null, slice, s, comparator, equality);
                        Components.Add(comp);
                    }
                    else if (comparator.Equals(ComparatorType.INTEGERTYPE.TypeName))
                    {
                        Serializer<int> s = IntegerSerializer.Instance;
                        equality = GetComponentEquality(bytescopy.Get());
                        slice = data.Slice();
                        Component<int> comp = new Component<int>(0, slice, s, comparator, equality);
                        Components.Add(comp);
                    }
                    else if (comparator.Equals(ComparatorType.LONGTYPE.TypeName))
                    {
                        Serializer<long> s = LongSerializer.Instance;
                        equality = GetComponentEquality(bytescopy.Get());
                        slice = data.Slice();
                        Component<long> comp = new Component<long>(0, slice, s, comparator, equality);
                        Components.Add(comp);
                    }
                    else if (comparator.Equals(ComparatorType.TIMEUUIDTYPE.TypeName))
                    {
                        Serializer<System.Guid> s = TimeUUIDSerializer.Instance;
                        equality = GetComponentEquality(bytescopy.Get());
                        slice = data.Slice();
                        Component<System.Guid> comp = new Component<System.Guid>(default(Guid), slice, s, comparator, equality);
                        Components.Add(comp);
                    }
                    else if (comparator.Equals(ComparatorType.UUIDTYPE.TypeName))
                    {
                        Serializer<System.Guid> s = UUIDSerializer.Instance;
                        equality = GetComponentEquality(bytescopy.Get());
                        slice = data.Slice();
                        Component<System.Guid> comp = new Component<System.Guid>(default(Guid), slice, s, comparator, equality);
                        Components.Add(comp);
                    }
                    else if (comparator.Equals(ComparatorType.LEXICALUUIDTYPE.TypeName))
                    {
                        Serializer<System.Guid> s = UUIDSerializer.Instance;
                        equality = GetComponentEquality(bytescopy.Get());
                        slice = data.Slice();
                        Component<System.Guid> comp = new Component<System.Guid>(default(Guid), slice, s, comparator, equality);
                        Components.Add(comp);
                    }
                    else if (comparator.Equals(ComparatorType.DATETYPE.TypeName))
                    {
                        Serializer<DateTime> s = DateSerializer.Instance;
                        equality = GetComponentEquality(bytescopy.Get());
                        slice = data.Slice();
                        Component<DateTime> comp = new Component<DateTime>(default(DateTime), slice, s, comparator, equality);
                        Components.Add(comp);
                    }
                }
                else
                {
                    throw new NullReferenceException("Missing component data in composite type");
                }
                i++;
            }
        }
        public byte ConvertComponentEqualityToByte(ComponentEquality eq)
        {
            if (eq == ComponentEquality.EQUAL)
            {
                return (byte)0;
            }
            else if (eq == ComponentEquality.GREATER_THAN_EQUAL)
            {
                return (byte)1;
            }
            else
            {
                return unchecked((byte)-1);
            }
        }
        public ComponentEquality GetComponentEquality(byte b)
        {
            if (b == unchecked((byte)-1))
            {
                return ComponentEquality.LESS_THAN_EQUAL;
            }
            else if (b == (byte)0)
            {
                return ComponentEquality.EQUAL;
            }
            else
            {
                return ComponentEquality.GREATER_THAN_EQUAL;
            }
        }
        private string GetComparator(int i, ByteBuffer bb)
        {
            string name = ComparatorForPosition(i);
            if (name != null)
            {
                return name;
            }
            if (!Dynamic)
            {
                if (bb.HasRemaining)
                {
                    return ComparatorType.BYTESTYPE.TypeName;
                }
                else
                {
                    return null;
                }
            }
            if (bb.HasRemaining)
            {
                try
                {
                    int header = GetShortLength(bb);
                    if ((header & 0x8000) == 0)
                    {
                        ByteBuffer nameBuffer = GetBytes(bb, header).Duplicate();
                        name = BitConverter.ToString(nameBuffer.GetBuffer(), 0);
                    }
                    else
                    {
                        byte a = (byte)(header & 0xFF);
                        name = DEFAULT_ALIAS_TO_COMPARATOR_MAPPING[a];
                        if (name == null)
                        {
                            a = (byte)Char.ToLower((char)a);
                            name = AliasToComparatorDictionary[a];
                            if (name != null)
                            {
                                name += "(reversed=true)";
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                }
            }
            if ((name != null) && (name.Length == 0))
            {
                name = null;
            }
            return name;
        }
        /// <summary>
        /// TODO - fix this method, doesn't seem right
        /// </summary>
        /// <param name="bb"></param>
        /// <returns></returns>
        protected static int GetShortLength(ByteBuffer bb)
        {
            int length = (bb.Get() & 0xFF) << 8;
            return length | (bb.Get() & 0xFF);
            // return bb.Get();
        }
        protected static ByteBuffer GetBytes(ByteBuffer bb, int length)
        {
            ByteBuffer copy = bb.Duplicate();
            copy.Limit = copy.Position + length;
            bb.Position = bb.Position + length;
            return copy;
        }
        protected static ByteBuffer GetWithShortLength(ByteBuffer bb)
        {
            int length = GetShortLength(bb);
            return GetBytes(bb, length);
        }
    }
}